# -*- coding: utf-8 -*-
"""
告警管理模块
负责告警的去重、聚合和发送
"""

import time
import json
import hashlib
import requests
from typing import Dict, Any, List, Optional
from datetime import datetime, time as dt_time
from collections import defaultdict
import logging

from config import config

logger = logging.getLogger(__name__)


class AlertLevel:
    """告警级别"""
    CRITICAL = "critical"  # 紧急
    SEVERE = "severe"      # 严重
    WARNING = "warning"    # 警告
    INFO = "info"          # 信息


class AlertType:
    """告警类型"""
    DROP_TABLE = "drop_table"
    DROP_DATABASE = "drop_database"
    TABLE_OVERWRITE = "table_overwrite"
    DATA_FLUCTUATION = "data_fluctuation"
    BATCH_DELETE = "batch_delete"


class Alert:
    """告警对象"""
    
    def __init__(self, alert_type: str, level: str, database: str, 
                 table: str = None, user: str = None, details: Dict[str, Any] = None):
        self.alert_type = alert_type
        self.level = level
        self.database = database
        self.table = table
        self.user = user
        self.details = details or {}
        self.timestamp = datetime.now()
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            'alert_type': self.alert_type,
            'level': self.level,
            'database': self.database,
            'table': self.table,
            'user': self.user,
            'details': self.details,
            'timestamp': self.timestamp.strftime('%Y-%m-%d %H:%M:%S')
        }
    
    def get_hash(self) -> str:
        """获取告警哈希值，用于去重"""
        key = f"{self.alert_type}:{self.database}:{self.table}:{self.level}"
        return hashlib.md5(key.encode()).hexdigest()


class AlertManager:
    """告警管理器"""
    
    # 告警级别对应的中文名称
    LEVEL_NAMES = {
        AlertLevel.CRITICAL: "紧急",
        AlertLevel.SEVERE: "严重",
        AlertLevel.WARNING: "警告",
        AlertLevel.INFO: "信息"
    }
    
    # 告警类型对应的中文名称
    TYPE_NAMES = {
        AlertType.DROP_TABLE: "删除表",
        AlertType.DROP_DATABASE: "删除数据库",
        AlertType.TABLE_OVERWRITE: "表覆盖",
        AlertType.DATA_FLUCTUATION: "数据量波动",
        AlertType.BATCH_DELETE: "批量删除"
    }
    
    # 告警级别对应的颜色
    LEVEL_COLORS = {
        AlertLevel.CRITICAL: "red",
        AlertLevel.SEVERE: "orange",
        AlertLevel.WARNING: "yellow",
        AlertLevel.INFO: "blue"
    }
    
    def __init__(self):
        self.webhook_url = config.feishu_webhook_url
        self.dedup_window = config.feishu_dedup_window
        self.aggregate_window = config.feishu_aggregate_window
        self.silent_periods = config.feishu_silent_periods
        
        # 告警去重缓存：{alert_hash: timestamp}
        self._dedup_cache: Dict[str, float] = {}
        
        # 告警聚合缓存：{alert_type: [alerts]}
        self._aggregate_cache: Dict[str, List[Alert]] = defaultdict(list)
        self._last_aggregate_time = time.time()
    
    def send_alert(self, alert: Alert) -> bool:
        """
        发送告警
        
        Args:
            alert: 告警对象
        
        Returns:
            是否发送成功
        """
        # 检查是否在静默时段
        if self._is_silent_period():
            logger.info(f"当前在静默时段，跳过告警: {alert.to_dict()}")
            return False
        
        # 告警去重
        if self._is_duplicate(alert):
            logger.info(f"告警已去重: {alert.to_dict()}")
            return False
        
        # 添加到聚合缓存
        self._aggregate_cache[alert.alert_type].append(alert)
        
        # 检查是否需要立即发送
        if self._should_send_immediately(alert):
            return self._send_now(alert)
        
        # 检查聚合窗口是否到期
        if time.time() - self._last_aggregate_time >= self.aggregate_window:
            return self._send_aggregated_alerts()
        
        return True
    
    def _is_silent_period(self) -> bool:
        """检查是否在静默时段"""
        if not self.silent_periods:
            return False
        
        now = datetime.now().time()
        
        for period in self.silent_periods:
            start = datetime.strptime(period['start'], '%H:%M').time()
            end = datetime.strptime(period['end'], '%H:%M').time()
            
            if start <= now <= end:
                return True
        
        return False
    
    def _is_duplicate(self, alert: Alert) -> bool:
        """检查告警是否重复"""
        alert_hash = alert.get_hash()
        now = time.time()
        
        # 清理过期的去重缓存
        expired_keys = [k for k, v in self._dedup_cache.items() 
                       if now - v > self.dedup_window]
        for k in expired_keys:
            del self._dedup_cache[k]
        
        # 检查是否重复
        if alert_hash in self._dedup_cache:
            return True
        
        # 记录告警
        self._dedup_cache[alert_hash] = now
        return False
    
    def _should_send_immediately(self, alert: Alert) -> bool:
        """判断是否需要立即发送告警"""
        # 紧急和严重级别立即发送
        return alert.level in [AlertLevel.CRITICAL, AlertLevel.SEVERE]
    
    def _send_now(self, alert: Alert) -> bool:
        """立即发送单个告警"""
        message = self._build_single_alert_message(alert)
        return self._send_to_feishu(message, alert.level)
    
    def _send_aggregated_alerts(self) -> bool:
        """发送聚合告警"""
        if not self._aggregate_cache:
            return True
        
        # 按告警类型分组发送
        success = True
        for alert_type, alerts in self._aggregate_cache.items():
            if alerts:
                message = self._build_aggregated_alert_message(alert_type, alerts)
                # 使用最高级别
                max_level = self._get_max_level(alerts)
                if not self._send_to_feishu(message, max_level):
                    success = False
        
        # 清空聚合缓存
        self._aggregate_cache.clear()
        self._last_aggregate_time = time.time()
        
        return success
    
    def _get_max_level(self, alerts: List[Alert]) -> str:
        """获取告警列表中的最高级别"""
        level_priority = {
            AlertLevel.CRITICAL: 4,
            AlertLevel.SEVERE: 3,
            AlertLevel.WARNING: 2,
            AlertLevel.INFO: 1
        }
        
        max_level = AlertLevel.INFO
        max_priority = 0
        
        for alert in alerts:
            priority = level_priority.get(alert.level, 0)
            if priority > max_priority:
                max_priority = priority
                max_level = alert.level
        
        return max_level
    
    def _build_single_alert_message(self, alert: Alert) -> Dict[str, Any]:
        """构建单个告警消息"""
        level_name = self.LEVEL_NAMES.get(alert.level, alert.level)
        type_name = self.TYPE_NAMES.get(alert.alert_type, alert.alert_type)
        color = self.LEVEL_COLORS.get(alert.level, "blue")
        
        # 构建详情字段
        fields = [
            {"is_short": True, "text": {"tag": "lark_md", "content": f"**告警级别：**\n{level_name}"}},
            {"is_short": True, "text": {"tag": "lark_md", "content": f"**告警类型：**\n{type_name}"}},
            {"is_short": True, "text": {"tag": "lark_md", "content": f"**数据库：**\n{alert.database}"}},
        ]
        
        if alert.table:
            fields.append({
                "is_short": True, 
                "text": {"tag": "lark_md", "content": f"**表名：**\n{alert.table}"}
            })
        
        if alert.user:
            fields.append({
                "is_short": True, 
                "text": {"tag": "lark_md", "content": f"**操作用户：**\n{alert.user}"}
            })
        
        fields.append({
            "is_short": True, 
            "text": {"tag": "lark_md", "content": f"**操作时间：**\n{alert.timestamp.strftime('%Y-%m-%d %H:%M:%S')}"}
        })
        
        # 添加详细信息
        if alert.details:
            detail_text = "\n".join([f"- {k}: {v}" for k, v in alert.details.items()])
            fields.append({
                "is_short": False,
                "text": {"tag": "lark_md", "content": f"**详细信息：**\n{detail_text}"}
            })
        
        # 构建飞书消息卡片
        card = {
            "msg_type": "interactive",
            "card": {
                "header": {
                    "title": {
                        "tag": "plain_text",
                        "content": "🚨 Hive元数据告警"
                    },
                    "template": color
                },
                "elements": [
                    {
                        "tag": "div",
                        "fields": fields
                    },
                    {
                        "tag": "hr"
                    },
                    {
                        "tag": "note",
                        "elements": [
                            {
                                "tag": "plain_text",
                                "content": "如有疑问，请联系数据平台团队"
                            }
                        ]
                    }
                ]
            }
        }
        
        # 添加@用户
        at_users = config.feishu_at_users.get(alert.level, [])
        if at_users:
            card["card"]["elements"].insert(0, {
                "tag": "div",
                "text": {
                    "tag": "lark_md",
                    "content": " ".join([f"<at user_id=\"{uid}\"></at>" for uid in at_users])
                }
            })
        
        return card
    
    def _build_aggregated_alert_message(self, alert_type: str, alerts: List[Alert]) -> Dict[str, Any]:
        """构建聚合告警消息"""
        type_name = self.TYPE_NAMES.get(alert_type, alert_type)
        max_level = self._get_max_level(alerts)
        level_name = self.LEVEL_NAMES.get(max_level, max_level)
        color = self.LEVEL_COLORS.get(max_level, "blue")
        
        # 统计信息
        db_count = len(set(a.database for a in alerts))
        table_count = len(set(f"{a.database}.{a.table}" for a in alerts if a.table))
        
        # 构建告警列表
        alert_list = []
        for alert in alerts[:10]:  # 最多显示10条
            item = f"• {alert.database}"
            if alert.table:
                item += f".{alert.table}"
            item += f" ({alert.timestamp.strftime('%H:%M:%S')})"
            alert_list.append(item)
        
        if len(alerts) > 10:
            alert_list.append(f"... 还有 {len(alerts) - 10} 条告警")
        
        alert_list_text = "\n".join(alert_list)
        
        card = {
            "msg_type": "interactive",
            "card": {
                "header": {
                    "title": {
                        "tag": "plain_text",
                        "content": f"🚨 Hive元数据批量告警 ({len(alerts)}条)"
                    },
                    "template": color
                },
                "elements": [
                    {
                        "tag": "div",
                        "fields": [
                            {"is_short": True, "text": {"tag": "lark_md", "content": f"**告警级别：**\n{level_name}"}},
                            {"is_short": True, "text": {"tag": "lark_md", "content": f"**告警类型：**\n{type_name}"}},
                            {"is_short": True, "text": {"tag": "lark_md", "content": f"**涉及数据库：**\n{db_count}个"}},
                            {"is_short": True, "text": {"tag": "lark_md", "content": f"**涉及表：**\n{table_count}张"}},
                        ]
                    },
                    {
                        "tag": "div",
                        "text": {
                            "tag": "lark_md",
                            "content": f"**告警详情：**\n{alert_list_text}"
                        }
                    },
                    {
                        "tag": "hr"
                    },
                    {
                        "tag": "note",
                        "elements": [
                            {
                                "tag": "plain_text",
                                "content": "检测到批量操作，请及时确认是否为正常操作"
                            }
                        ]
                    }
                ]
            }
        }
        
        # 添加@用户
        at_users = config.feishu_at_users.get(max_level, [])
        if at_users:
            card["card"]["elements"].insert(0, {
                "tag": "div",
                "text": {
                    "tag": "lark_md",
                    "content": " ".join([f"<at user_id=\"{uid}\"></at>" for uid in at_users])
                }
            })
        
        return card
    
    def _send_to_feishu(self, message: Dict[str, Any], level: str) -> bool:
        """
        发送消息到飞书
        
        Args:
            message: 消息内容
            level: 告警级别
        
        Returns:
            是否发送成功
        """
        if not self.webhook_url:
            logger.warning("未配置飞书Webhook URL，跳过发送")
            return False
        
        try:
            response = requests.post(
                self.webhook_url,
                json=message,
                headers={'Content-Type': 'application/json'},
                timeout=10
            )
            
            if response.status_code == 200:
                result = response.json()
                if result.get('code') == 0:
                    logger.info(f"告警发送成功: level={level}")
                    return True
                else:
                    logger.error(f"告警发送失败: {result}")
                    return False
            else:
                logger.error(f"告警发送失败: status_code={response.status_code}")
                return False
        
        except Exception as e:
            logger.error(f"告警发送异常: {e}", exc_info=True)
            return False
    
    def flush(self):
        """刷新缓存，发送所有待发送的告警"""
        self._send_aggregated_alerts()


# 全局告警管理器实例
alert_manager = AlertManager()

